using System;
using System.Web;
using System.Web.Caching;
using Microsoft.SharePoint;

namespace BoldBrick.SharePoint.CommonControls.Utils
{
	/// <summary>
	/// This class provides some utils for Cache usage
	/// </summary>
	public static class CacheHelper
	{
		#region Set Methods

		/// <summary>
		/// Adds item to cache.
		/// </summary>
		/// <param name="key">Key of the cached item.</param>
		/// <param name="value">Value of the item.</param>
		public static void Set(string key, object value)
		{
			set(key, value, null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
		}

		/// <summary>
		/// Adds item to cache for specified time
		/// </summary>
		/// <param name="key">Key of the cached item.</param>
		/// <param name="value">Value of the item.</param>
		/// <param name="absoluteExpirationInterval">Absolute expiratio of the cache</param>
		/// <param name="slidingExpirationInterval">Sliding expiration of the cache</param>
		/// <param name="priority"></param>
		public static void Set(string key, object value, DateTime absoluteExpirationInterval, TimeSpan slidingExpirationInterval, CacheItemPriority priority)
		{
			set(key, value, null, absoluteExpirationInterval, slidingExpirationInterval, priority, null);
		}

		/// <summary>
		/// Adds item to cache with dependency
		/// </summary>
		/// <param name="key">Key of the cached item.</param>
		/// <param name="value">Value of the item.</param>
		/// <param name="cacheDependencyKeys">Key for dependency</param>
		public static void Set(string key, object value, string[] cacheDependencyKeys)
		{
			set(key, value, cacheDependencyKeys, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
		}

		/// <summary>
		/// Adds to Cache item, that is dependant on specified SPWeb. Then it is possible to clear all 
		/// web-dependent items with CacheHelper.ClearCache(SPWeb web) method.
		/// </summary>
		/// <param name="key">Key for item.</param>
		/// <param name="value">Value of the item.</param>
		/// <param name="web">SPWeb object, that inserted item is dependent on.</param>
		public static void Set(string key, object value, SPWeb web)
		{
			Set(key, value, web, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.Normal);
		}

		/// <summary>
		/// Adds item to cache for specified time
		/// </summary>
		/// <param name="key">Key of the cached item.</param>
		/// <param name="value">Value of the item.</param>
		/// <param name="web">SPWeb object, that inserted item is dependent on.</param>
		/// <param name="absoluteExpirationInterval">Absolute expiratio of the cache</param>
		/// <param name="slidingExpirationInterval">Sliding expiration of the cache</param>
		/// <param name="priority"></param>
		public static void Set(string key, object value, SPWeb web, DateTime absoluteExpirationInterval, TimeSpan slidingExpirationInterval, CacheItemPriority priority)
		{
			if (web == null)
			{
				set(key, value, null, absoluteExpirationInterval, slidingExpirationInterval, priority, null);
			}
			else
			{
				string dependencyKey = CacheDependencyHelper.GetDependencyKey(web);
				set(key, value, new string[] {dependencyKey}, absoluteExpirationInterval, slidingExpirationInterval, priority, null);
			}
		}

		#endregion

		#region Get Methods

		/// <summary>
		/// This method returns a value from Cache by key
		/// </summary>
		/// <typeparam name="TType">Type of returned value</typeparam>
		/// <param name="key">Key of the value</param>
		/// <returns>Returns a value from Cache by key</returns>
		public static TType Get<TType>(string key)
		{
            object obj = HttpRuntime.Cache[key];
			if (obj == null)
			{
				if (typeof(string) == typeof(TType))
				{
					//obj = string.Empty;
				}
				else if (typeof(bool) == typeof(TType))
				{
					obj = false;
				}
				else if (typeof(int) == typeof(TType))
				{
					obj = 0;
				}
				else if (typeof(DateTime) == typeof(TType))
				{
					obj = DateTime.MinValue;
				}
			}
			return (TType)obj;
		}

		#endregion

		#region Clear Methods

		/// <summary>
		/// Clears all Cache items dependent on specified web.
		/// </summary>
		/// <param name="web"></param>
		/// <param name="recursive">Indicates if cache of subwebs should be recursively cleared.</param>
		public static void ClearCache(SPWeb web, bool recursive)
		{
			if (web != null)
			{
				string key = CacheDependencyHelper.GetDependencyKey(web);
				clearCache(key);
				
				if (recursive)
				{
					foreach (SPWeb subWeb in web.Webs)
					{
						ClearCache(subWeb, true);
						subWeb.Dispose();
					}
				}
			}
		}

		/// <summary>
		/// Clear all cached data depended on specified dependency key
		/// </summary>
		/// <param name="dependencyKey">Dependency key</param>
		public static void ClearCache(string dependencyKey)
		{
			clearCache(dependencyKey);
		}

		/// <summary>
		/// Changes the value of specified key, resulting in clearing all dependent cache items.
		/// </summary>
		/// <param name="dependencyKey"></param>
		private static void clearCache(string dependencyKey)
		{
			randomizeCache(dependencyKey);
		}

		#endregion

		

		#region Private Methods

		/// <summary>
		/// Fills supplied cache item with random number.
		/// </summary>
		/// <param name="key">Key of the item to randomize.</param>
		private static void randomizeCache(string key)
		{
            HttpRuntime.Cache.Insert(key, (new Random()).Next(), null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable, null);
		}
		
		

		private static void set(string key, object value, string[] dependencyKeys, DateTime absoluteExpirationInterval, TimeSpan slidingExpirationInterval, CacheItemPriority priority, CacheItemRemovedCallback callback)
		{
			if ( value == null )
			{
				HttpRuntime.Cache.Remove(key);
				return;
			}
			
			// If any dependecy keys are supplied, create them if they are not present already.
			if (dependencyKeys != null && dependencyKeys.Length > 0)
			{
				foreach (string dependencyKey in dependencyKeys)
				{
					if (!IsCached(dependencyKey))
					{
						randomizeCache(dependencyKey);
					}
				}
			}
			
			CacheDependency dependency = new CacheDependency(null, dependencyKeys);

			//this.context.Cache.Insert(key, value, dependency, absoluteExpirationInterval, slidingExpirationInterval, CacheItemPriority.NotRemovable, null);
            HttpRuntime.Cache.Insert(key, value, dependency, absoluteExpirationInterval, slidingExpirationInterval, priority, callback);
            
		}

		#endregion

		#region ISCached

		/// <summary>
		/// Returns true if object is in cache
		/// </summary>
		/// <param name="key">Key of the object</param>
		/// <returns>Returns true if object is in cache</returns>
		public static bool IsCached(string key)
		{
			bool isCached = HttpRuntime.Cache[key] != null;
			return isCached;
		}

		#endregion

	}
}